<script>
import {
    TEXT,
    SELECT,
    PASSWORD,
    TEXTAREA,
    READIO,
    DATA_PICKER
} from '@/config/form-type-config'
import deepClone from '@/utils/deepClone'
export default {
    name: 'FormCreator',
    props: {
        config: {
            type: Object,
            required: true
        }
    },
    data() {
        return {
            innerConfig: deepClone(this.config),
            formData: {},
        }
    },
    created() {
        const { columns, rules } = this.innerConfig;
        for (let k in rules) {
            rules[k].forEach(r => {
                if (r.validator) {
                    // 把自定义的验证器改变this指向为当前组件
                    r.validator = r.validator.bind(this);
                }
            })
        }
        this.refFormData(columns);
    },
    methods: {
        refFormData(columns) {
            let { formData } = this;
            if (!columns) return;
            columns.forEach((row, rowIndex) => {
                row.forEach((item, colIndex) => {
                    if (Object.prototype.hasOwnProperty.call(formData,item.key)) {
                        throw new Error(`行${rowIndex + 1}_列${colIndex + 1}已经存在相同的key:+ ${item.key}`)
                    }
                    this.$set(formData, item.key, item.value);
                })
            })
        },
        renderFormItem(item) {
            let { type, attrs, key } = item;
            let { formData } = this;
            switch (type) {
                case TEXT:
                case PASSWORD:
                case TEXTAREA:
                    return <el-input attrs={attrs} v-model={formData[key]}></el-input>
                case SELECT:
                    return <el-select attrs={attrs} v-model={formData[key]}>
                        {item?.options.map(sel => {
                            return <el-option value={sel.value} label={sel.label}></el-option>
                        })}
                    </el-select>
                case READIO:
                    return item?.radios.map(rad => {
                        return <el-radio attrs={rad.attrs} v-model={formData[key]} label={rad.label}>
                        </el-radio>
                    })
                case DATA_PICKER:
                    return <el-date-picker attrs={attrs} v-model={formData[key]}></el-date-picker>
                default:
                    return <el-tag type="danger">无效的输入框类型:{type}</el-tag>
            }
        },
        renderRows(rows) {
            return rows.map(row => {
                return <el-row gutter={20}>
                    {this.renderColumns(row)}
                </el-row>
            })
        },
        renderColumns(columns) {
            return columns.map(col => {
                return (
                    <el-col span={col.colspan}>
                        <el-form-item label={col.label} prop={col.key}>
                            {this.renderFormItem(col)}
                        </el-form-item>
                    </el-col>
                )
            })
        },
        // 触发外部绑定的commit获取表单内容
        passData() {
            this.$refs.form.validate(valid => {
                if (valid) {
                    return this.$emit('commit', deepClone(this.formData))
                } else {
                    return false;
                }
            })
        },
        // 重置
        reset() {
            this.$refs.form.resetFields();
        }
    },
    render() {
        let { $attrs, formData, $scopedSlots: { btn, title } } = this;
        let { title: textTitle, rules, columns } = this.innerConfig;
        return (
            <div>
                {title ? title(textTitle) : (
                    <h3 class='title'>{textTitle}</h3>
                )}
                <el-form ref="form" attrs={{ ...$attrs, model: formData }} rules={rules}>
                    {this.renderRows(columns)}
                </el-form>
                {btn ? btn({ reset: this.reset, getData: this.passData }) : (
                    <div class='center'>
                        <el-button type="primary" onClick={() => this.passData()}>提交</el-button>
                        <el-button type="info" onClick={() => this.reset()}>重置</el-button>
                    </div>
                )}
            </div>
        )
    }
}
</script>
<style scoped>
.title {
    margin-bottom: 10px;
}

.center {
    text-align: center;
}
</style>